﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using Caliburn.Micro;
using CardPlay.Client.Model;
using CardPlay.Model.CardModel;
using CardPlay.Model.GameModel;
using CardPlay.Model.Primitives;

namespace CardPlay.Client.ViewModels
{
    public class CardViewModel : PropertyChangedBase, ITreeNode, IHaveHotState
    {
        private readonly Card _card;
        private ITreeNode _parentNode;
        private Point _location;
        private bool _inHotState;
        private bool _hidden;
        private bool _isSelected;

        public CardViewModel(ITreeNode parent, Card card)
        {
            Contract.Requires<ArgumentNullException>(parent != null);
            Contract.Requires<ArgumentNullException>(card != null);

            _card = card;

            ParentNode = parent;
        }

        private void OnCardOnFlipped(object sender, EventArgs e)
        {
            NotifyOfPropertyChange(() => Card);
            NotifyOfPropertyChange(() => Visual);
        }

        public ITreeNode ParentNode
        {
            get { return _parentNode; }
            set
            {
                if (ParentNode != null)
                    Card.Flipped -= OnCardOnFlipped;

                _parentNode = value;

                if (ParentNode != null)
                    Card.Flipped += OnCardOnFlipped;
            }
        }

        public IEnumerable<ITreeNode> ChildNodes
        {
            get { return Enumerable.Empty<ITreeNode>(); }
        }

        public Card Card
        {
            get { return _card;  }
        }

        public bool InHotState
        {
            get { return _inHotState; }
            set
            {
                if ((InHotState == value) || (value && !PlayingContext.Game.IsActionPossibleAt(PartLocation))) return;

                _inHotState = value;
                NotifyOfPropertyChange(() => InHotState);
            }
        }

        public bool IsSelected
        {
            get { return _isSelected; }
            set
            {
                if (value == IsSelected) return;
                _isSelected = value;
                NotifyOfPropertyChange(() => IsSelected);
            }
        }

        public bool Hidden
        {
            get { return _hidden; }
            set
            {
                if (value == Hidden) return;
                _hidden = value;
                NotifyOfPropertyChange(() => Hidden);
            }
        }

        public PartLocation PartLocation
        {
            get { return ((PileViewModel) ParentNode).Pile.LocationOf(Card); }
        }

        public Point Location
        {
            get { return _location; }
            set
            {
                if (_location == value) return;
                _location = value;
                NotifyOfPropertyChange(() => Location);
            }
        }

        public Size Size
        {
            get { return PlayingContext.Canvas.Metrics.CardSize; }
        }

        public Rectangle Bounds
        {
            get { return new Rectangle(Location, Size); }
        }

        public object Visual
        {
            get { return PlayingContext.Canvas.ImageForCard(_card); }
        }

        private IPlayingContext PlayingContext
        {
            get { return this.GetService<IPlayingContext>(); }
        }

        public bool HitTest(Rectangle bounds)
        {
            return Bounds.IntersectsWith(bounds);
        }
    }
}